#include "Octaedre.hpp"

#include <algorithm>

using namespace std;

/**
 * Constructeur permettant d'initialiser l'Octaedre.
 *
 * @param base1 point de la base.
 * @param base2 point de la base.
 * @param base3 point de la base.
 * @param hauteur "sommet" de l'Octaedre, l'autre est obtenu par
 * symétrie.
 */
Octaedre::Octaedre(const Coord& base1, const Coord& base2, const Coord& base3,
		   const Coord& hauteur)
{	
  Vecteur Pbase1(base1,base2),Pbase2(base1,base3);
  Vecteur tmp(Pbase2+Pbase1);
  Coord base4(base1 + tmp); // 4 eme coord de la base
  Vecteur Pbase3(base4,base3), Pbase4(base4,base2);
  Vecteur arrete1(base1,hauteur),arrete4(base4,hauteur);
  Vecteur vNormal1(Pbase1^Pbase2); // normal de la base pyramide
  PseudoCentre = base1 + .5 * tmp;
  if (vNormal1*arrete1>0)
    vNormal1*=-1;
  Vecteur vNormal2(Pbase1^arrete1);
  if (vNormal2*vNormal1>0)
    vNormal2*=-1;
  Vecteur vNormal3(Pbase2^arrete1);
  if (vNormal3*vNormal1>0)
    vNormal3*=-1;
  Vecteur vNormal4(Pbase3^arrete4);
  if (vNormal4*vNormal1>0)
    vNormal4*=-1;
  Vecteur vNormal5(Pbase4^arrete4);
  if (vNormal5*vNormal1>0)
    vNormal5*=-1;
  // 4 plans qui composent la 1er pyramide
  listplan.push_back(Plan::SharedPtr (new Plan(vNormal2,hauteur)));
  listplan.push_back(Plan::SharedPtr (new Plan(vNormal3,hauteur)));
  listplan.push_back(Plan::SharedPtr (new Plan(vNormal4,hauteur)));
  listplan.push_back(Plan::SharedPtr (new Plan(vNormal5,hauteur)));
  // inversion de la hauteur
  Vecteur tmp1(base4,base1);
  Vecteur inverse=arrete4.reflect(tmp1);
  Coord hautinv(base4 + inverse);
  Vecteur arrete2(base1,hautinv),arrete3(base4,hautinv);
  vNormal1*=-1;
  Vecteur vNormal6(Pbase1^arrete2);
  if (vNormal6*vNormal1>0)
    vNormal6*=-1;
  Vecteur vNormal7(Pbase2^arrete2);
  if (vNormal7*vNormal1>0)
    vNormal7*=-1;
  Vecteur vNormal8(Pbase3^arrete3);
  if (vNormal8*vNormal1>0)
    vNormal8*=-1;
  Vecteur vNormal9(Pbase4^arrete3);
  if (vNormal9*vNormal1>0)
    vNormal9*=-1;
  listplan.push_back(Plan::SharedPtr (new Plan(vNormal6,hautinv)));
  listplan.push_back(Plan::SharedPtr (new Plan(vNormal7,hautinv)));
  listplan.push_back(Plan::SharedPtr (new Plan(vNormal8,hautinv)));
  listplan.push_back(Plan::SharedPtr (new Plan(vNormal9,hautinv)));
  // on prend l'intersection des plans
  listFC.push_back(FormeComposee::SharedPtr (new FormeComposee(inter,listplan[0].get(),listplan[1].get())));
  listFC.push_back(FormeComposee::SharedPtr (new FormeComposee(inter,listplan[2].get(),listplan[3].get())));
  listFC.push_back(FormeComposee::SharedPtr (new FormeComposee(inter,listplan[4].get(),listplan[5].get())));
  listFC.push_back(FormeComposee::SharedPtr (new FormeComposee(inter,listplan[6].get(),listplan[7].get())));
  listFC.push_back(FormeComposee::SharedPtr (new FormeComposee(inter,listFC[0].get(),listFC[1].get())));
  listFC.push_back(FormeComposee::SharedPtr (new FormeComposee(inter,listFC[2].get(),listFC[3].get())));
  form[0]=listFC[4].get();
  form[1]=listFC[5].get();
  op=inter;
	
  Nom = "Octaèdre";

  vector< double > distances;
  
  distances.push_back( Vecteur( PseudoCentre, base1 ).norme() );
  distances.push_back( Vecteur( PseudoCentre, base2 ).norme() );
  distances.push_back( Vecteur( PseudoCentre, base3 ).norme() );
  distances.push_back( Vecteur( PseudoCentre, hauteur ).norme() );

  PseudoRayon = sqrt( *max_element( distances.begin(), distances.end() ) );
}

/**
 * Le destructeur n'a rien de spécial à faire.
 */
Octaedre::~Octaedre()
{}
